﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Core.Model.Transmit;
using Core.Msg;
using log4net;

namespace Core.Transmit
{
    /// <summary>
    /// 通道协议基类型
    /// </summary>
    public abstract class TransmitChannelProtocol :INotifyPropertyChanged
    {

        #region IChannel 成员
        private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        public TransmitDeviceProtocol CurDevProtocol { get;protected set; }
        public event EventHandler OnNewMessage;
        protected readonly Dictionary<string, TransmitDeviceProtocol> protocols = new Dictionary<string, TransmitDeviceProtocol>();

        public NetType ChannelNetType { get; protected set; }
        protected virtual void LoadProtocol(TransmitDevice device)
        {
            try
            {
                if (device != null && !string.IsNullOrEmpty(device.Protocol))
                {
                    string strPath = Global.DataAccess.GetTransmitDevProtocolPath();
                    DirectoryInfo driverPath = new DirectoryInfo(strPath);
                    FileInfo[] files = driverPath.GetFiles();

                    for (int i = 0; i < files.Length; i++)
                    {
                        FileVersionInfo info = FileVersionInfo.GetVersionInfo(files[i].FullName);
                        if (info.ProductName != device.Protocol) continue;
                        if (files[i].Name.Contains(".dll") || files[i].Name.Contains(".DLL"))
                        {
                            string proPath = Path.Combine(strPath, files[i].Name);
                            Assembly asm = Assembly.Load(new AssemblyName() { CodeBase = proPath });
                            foreach (Type extype in asm.GetExportedTypes())
                            {
                                //确定type为类并且继承自(实现)TransmitDeviceProtocol
                                if (extype.IsClass && typeof(TransmitDeviceProtocol).IsAssignableFrom(extype))
                                {
                                    TransmitDeviceProtocol baseDevProtocol = (TransmitDeviceProtocol)Activator.CreateInstance(extype);
                                    List<TransmitData> dataItems = Global.DataAccess.GetTransmitData(device.Id);
                                    dataItems = baseDevProtocol.DeSerializeDataItems(dataItems);
                                    baseDevProtocol.Initialize(this,device, dataItems);
                                    protocols.Add(device.Id, baseDevProtocol);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _log.Error("协议加载出错:" + e.Message);
            }
        }

        public virtual void RaiseMessageEvent(RxTxCommand cmd)
        {
            if (cmd != null && OnNewMessage != null)
            {
                try
                {
                    OnNewMessage(new  RxTxCommand(cmd),EventArgs.Empty);
                }
                catch 
                {
                }
            }
        }
       
        public TransmitChannel ChlInfo { get; set; }
        public virtual bool Connected { get; protected set; }

        public abstract bool Start();

        public virtual void Stop()
        {
            try
            {
                foreach (KeyValuePair<string, TransmitDeviceProtocol> devProtocol in protocols)
                {
                    devProtocol.Value.Dev.IsConnected = false;
                    devProtocol.Value.TransDataItems.ForEach(sss=>sss.CurValue=0);
                }
            }
            catch 
            {
            }
           
        }

        /// <summary>
        /// 获取设备驱动
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        public TransmitDeviceProtocol GetDevProtocolByDevice(TransmitDevice device)
        {
            if (device == null)
                return null;
            foreach (KeyValuePair<string, TransmitDeviceProtocol> pair in protocols)
            {
                if (pair.Key == device.Id)
                {
                    return pair.Value;
                }
            }
            return null;
        }
        /// <summary>
        /// 通过设备Id获取设备
        /// </summary>
        /// <param name="devId"></param>
        /// <returns></returns>
        public TransmitDevice GetDeviceById(string devId)
        {
            if (string.IsNullOrEmpty(devId))
                return null;
            foreach (KeyValuePair<string, TransmitDeviceProtocol> pair in protocols)
            {
                if (pair.Key == devId)
                {
                    return pair.Value.Dev;
                }
            }
            return null;
        }
        /// <summary>
        /// 根据设备Id获取设备驱动
        /// </summary>
        /// <param name="devId"></param>
        /// <returns></returns>
        public TransmitDeviceProtocol GetDevProtocolByDevice(string devId)
        {
            foreach (KeyValuePair<string, TransmitDeviceProtocol> pair in protocols)
            {
                if (pair.Key == devId)
                {
                    return pair.Value;
                }
            }
            return null;
        }
        /// <summary>
        /// 获取通道内所有数据项
        /// </summary>
        /// <returns></returns>
        public List<TransmitData> GetChlDataItems()
        {
            List <TransmitData> dataItems = new List<TransmitData>();
            foreach (KeyValuePair<string, TransmitDeviceProtocol> pair in protocols)
            {
                if (pair.Value.TransDataItems.Count > 0)
                {
                    dataItems.AddRange(pair.Value.TransDataItems);
                }
            }
            return dataItems;
        }

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public enum NetType
    {
        SerialPort,
        TcpServer,
        TcpClient,
        UdpServer,
        UdpClient
    }
}
